/**
 * (created at 2010-12-27)
 */
package qiushuo.mysqlparser.recognizer;

/**
 * @author <a href="mailto:QiuShuo1985@gmail.com">QIU Shuo</a>
 */
public class CharReader {
    private char[] charList;
    /** current pointer: point to char ready to read */
    private int nextIndex = 0;
    private int mark = 0;

    public CharReader(String string) {
        if (string == null) throw new IllegalArgumentException("argument string is null!");
        charList = string.toCharArray();
    }

    public int getCurrentPosition() {
        return nextIndex;
    }

    public char[] getSubChars(int offset, int size) {
        if (offset < 0 || size < 0 || offset + size > charList.length) {
            throw new IllegalArgumentException("argument invalid: offset=" + offset + ", size=" + size);
        }
        char[] rst = new char[size];
        System.arraycopy(charList, offset, rst, 0, size);
        return rst;
    }

    public char[] getLeftChars() {
        int size = charList.length - nextIndex;
        char[] rst = new char[size];
        System.arraycopy(charList, nextIndex, rst, 0, size);
        return rst;
    }

    public boolean isNext(String str, int offset, boolean ignoreCase) {
        int size = str.length();
        if (nextIndex + size + offset > charList.length) return false;
        if (ignoreCase) {
            for (int i = 0; i < size; ++i) {
                char c2 = Character.toLowerCase(str.charAt(i));
                char c1 = Character.toLowerCase(charList[nextIndex + i + offset]);
                if (c1 != c2) {
                    return false;
                }
            }
        } else {
            for (int i = 0; i < size; ++i) {
                if (str.charAt(i) != charList[nextIndex + i + offset]) {
                    return false;
                }
            }
        }
        return true;
    }

    public boolean isNext(String str, boolean ignoreCase) {
        return isNext(str, 0, ignoreCase);
    }

    public boolean isNext(String str) {
        return isNext(str, 0, false);
    }

    public boolean isNext(char c, int offset) {
        int index = nextIndex + offset;
        if (index >= charList.length) return false;
        return charList[index] == c;
    }

    public boolean hasNext() {
        return nextIndex < charList.length;
    }

    /**
     * @param howMany if 1, then equals to {@link #hasNext()}
     */
    public boolean hasNext(int howMany) {
        return nextIndex + howMany <= charList.length;
    }

    /**
     * @param offset if 0, same character with {@link #next()} will be returned
     * @return char at index of <code>currentIndex + offset</code>.
     * @throws StringIndexOutOfBoundsException
     */
    public char lookAhead(int offset) {
        if (nextIndex + offset >= charList.length) {
            throw new StringIndexOutOfBoundsException("index " + nextIndex + " >= length " + charList.length);
        }
        return charList[nextIndex + offset];
    }

    /**
     * move the current position pointer
     * 
     * @throws StringIndexOutOfBoundsException If thrown, pointer dose not move
     */
    public char next() {
        if (nextIndex >= charList.length) {
            throw new StringIndexOutOfBoundsException("index " + nextIndex + " >= length " + charList.length);
        }
        return charList[nextIndex++];
    }

    /**
     * move forward current pointer with offset.
     * 
     * @param offset if 0, no effect
     */
    public void skipForce(final int offset) {
        nextIndex += offset;
    }

    public void backForce() {
        --nextIndex;
    }

    /**
     * embedded mark-reset is not supported
     */
    public void mark() {
        mark = nextIndex;
    }

    /**
     * embedded mark-reset is not supported
     */
    public void reset() {
        nextIndex = mark;
    }

    @Override
    public String toString() {
        return new String(getLeftChars());
    }

}
